package com.wkbb.sports.service.impl;

import com.wkbb.common.constants.RedisKeyConstant;
import com.wkbb.common.dto.ResultDTO;
import com.wkbb.common.dto.basic.OrganizationDto;
import com.wkbb.common.redis.RedisTemplateUtil;
import com.wkbb.sports.dto.*;
import com.wkbb.sports.dto.ScoreRuleDto.ScoreScope;
import com.wkbb.sports.feign.BasicFeignService;
import com.wkbb.sports.mapper.HlifeOrgGradeMapper;
import com.wkbb.sports.mapper.HlifePhysicalMapper;
import com.wkbb.sports.mapper.HlifePhysicalRuleItemMapper;
import com.wkbb.sports.mapper.HlifePhysicalRuleMapper;
import com.wkbb.sports.mapper.HlifePhysicalRulePlusesMapper;
import com.wkbb.sports.model.HlifeOrgGrade;
import com.wkbb.sports.model.HlifePhysical;
import com.wkbb.sports.service.RuleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

@Service
public class RuleServiceImpl implements RuleService {

	@Autowired
	private RedisTemplateUtil redisTemplateUtil;

    @Autowired
    private HlifeOrgGradeMapper hlifeOrgGradeMapper;


    @Autowired
    private HlifePhysicalMapper hlifePhysicalMapper;

    @Autowired
    private HlifePhysicalRuleMapper hlifePhysicalRuleMapper;

    @Autowired
    private HlifePhysicalRuleItemMapper hlifePhysicalRuleItemMapper;

    @Autowired
    private HlifePhysicalRulePlusesMapper hlifePhysicalRulePlusesMapper;
    
    @Autowired
    private BasicFeignService basicFeignService;
    

	@Override
	public List<HlifeOrgGrade> queryOrgGradeList(Long orgId) throws Exception {
		Map<String, Object> params = new HashMap<>();
		params.put("orgId", orgId);
		return hlifeOrgGradeMapper.getListByMapParams(params);
	}

	@Override
	public List<ScoreRuleDto> queryScoreRuleTypeList(Long orgId) throws Exception {
//		String redisKey = RedisKeyConstant.SPORTS + "queryScoreRuleTypeList:"+orgId;
//		List<ScoreRuleDto> rules;
//		rules = (List<ScoreRuleDto>) redisTemplateUtil.get(redisKey);
//		if (rules!= null) return rules;
		OrganizationDto orgDto = getOrgDto(orgId);

        List<PhysicalDto> physicalList = hlifePhysicalMapper.queryPhysicalListByOrg(orgId, orgDto.getProvinceId(), orgDto.getCityId());

        if(physicalList == null || physicalList.size() <= 0) {
        	throw new RuntimeException("can not find physical for org: " + orgId);
        }

        String ids = getPhysicalIds(physicalList);

        List<PhysicalRuleDto> physicalRuleList = hlifePhysicalRuleMapper.queryRuleListByPhysicalIds(ids,null);

		List<ScoreRuleDto> rules = new ArrayList<>();
        for(PhysicalDto physical : physicalList) {
            for(PhysicalRuleDto physicalRule : physicalRuleList) {
        		if(compareValue(physical.getId(), physicalRule.getPhysicalId())) {
        			ScoreRuleDto rule = new ScoreRuleDto();
        			rule.setProjectKind(physical.getProjectKind());
        			rule.setProjectId(physical.getId());
        			rule.setProjectName(physical.getName());
        			rule.setMarkType(physical.getMarkType());
        			rule.setModelType(physical.getModelType());
        			rule.setGradeId(physicalRule.getGradeId());
        			rules.add(rule);
        		}
        	}
        }


        return rules;
	}

	private OrganizationDto getOrgDto(Long orgId) {
		ResultDTO<OrganizationDto> resultDto = basicFeignService.getOrgById(orgId);
		
		OrganizationDto orgDto = resultDto.getData();
		
		if(orgDto == null) {
			return new OrganizationDto();
		}
		
		return orgDto;
	}

	private String getPhysicalIds(List<PhysicalDto> physicalList) {
		Long[] ids = new Long[physicalList.size()];
        int i = 0;
        for(PhysicalDto physical : physicalList) {
        	Long physicalId = physical.getId();
        	ids[i] = physicalId;
        	i++;
        }
        String arrays = Arrays.toString(ids);
        arrays = arrays.replace('[', '(');
        arrays = arrays.replace(']', ')');
		return arrays;
	}

	private String getphysicalRuleIds(List<PhysicalRuleDto> physicalList) {
		Long[] ids = new Long[physicalList.size()];
        int i = 0;
        for(PhysicalRuleDto physical : physicalList) {
        	Long physicalId = physical.getId();
        	ids[i] = physicalId;
        	i++;
        }
        String arrays = Arrays.toString(ids);
        arrays = arrays.replace('[', '(');
        arrays = arrays.replace(']', ')');
		return arrays;
	}

	@Override
	public List<ScoreRuleDto> queryScoreRuleListByProjectId(Long projectId) throws Exception {
		
		HlifePhysical physical = hlifePhysicalMapper.getByPrimaryKey(projectId);
        
        if(physical == null) {
        	throw new RuntimeException("can not find physical: " + projectId);
        }
        
        PhysicalDto physicalDto = new PhysicalDto();
        
        physicalDto.setId(physical.getId());
        physicalDto.setName(physical.getName());
        physicalDto.setProjectKind(physical.getProjectKind());
        physicalDto.setMarkType(physical.getMarkType());
        physicalDto.setModelType(physical.getModelType());
        
        List<PhysicalDto> physicalList = new ArrayList<>();
        
        physicalList.add(physicalDto);
        
        return buildScoreRules(physicalList,null);
	}
	
	@Override
	public List<ScoreRuleDto> queryScoreRuleList(Long orgId) throws Exception {
		
		OrganizationDto orgDto = getOrgDto(orgId);
		
        List<PhysicalDto> physicalList = hlifePhysicalMapper.queryPhysicalListByOrg(orgId, orgDto.getProvinceId(), orgDto.getCityId());
        
        if(physicalList == null || physicalList.size() <= 0) {
        	throw new RuntimeException("can not find physical for org: " + orgId);
        }
        
        return buildScoreRules(physicalList,null);
	}

	@Override
	public ScoreRuleDto queryScoreRule(Long gradeId,Byte projectKind) {
		List<PhysicalDto> physicalList = hlifePhysicalMapper.queryScoreRule(gradeId,projectKind);
		if (!physicalList.isEmpty()){
			List<ScoreRuleDto> scoreRuleDtos = buildScoreRules(physicalList,gradeId);
			if (!scoreRuleDtos.isEmpty()){
				return scoreRuleDtos.get(0);
			}
		}
		return null;
	}

	private List<ScoreRuleDto> buildScoreRules(List<PhysicalDto> physicalList,Long gradeId) {
		String ids = getPhysicalIds(physicalList);
        
        List<PhysicalRuleDto> physicalRuleList = hlifePhysicalRuleMapper.queryRuleListByPhysicalIds(ids,gradeId);

//        List<PhysicalRuleItemDto> physicalRuleItemList = hlifePhysicalRuleItemMapper.queryRuleItemListByPhysicalIds(ids);
//        List<PhysicalRulePlusesDto> physicalRulePlusList = hlifePhysicalRulePlusesMapper.queryRulePlusListByPhysicalIds(ids);
		String ruleIds = getphysicalRuleIds(physicalRuleList);
		List<PhysicalRuleItemDto> physicalRuleItemList = hlifePhysicalRuleItemMapper.queryRuleItemListByPhysicalIds(ruleIds);
        List<PhysicalRulePlusesDto> physicalRulePlusList = hlifePhysicalRulePlusesMapper.queryRulePlusListByPhysicalIds(ruleIds);

        List<ScoreRuleDto> rules = new ArrayList<>();
        for(PhysicalDto physical : physicalList) {
        	for(PhysicalRuleDto physicalRule : physicalRuleList) {
        		if(compareValue(physical.getId(), physicalRule.getPhysicalId())) {
        			ScoreRuleDto rule = new ScoreRuleDto();
        			rule.setProjectKind(physical.getProjectKind());
        			rule.setProjectId(physical.getId());
        			rule.setProjectName(physical.getName());
        			rule.setMarkType(physical.getMarkType());
        			rule.setModelType(physical.getModelType());
        			rule.setGradeId(physicalRule.getGradeId());
        			rule.setRuleType(physicalRule.getRuleType());
					rule.setScore(0);
					rule.setPlusScore(0);
        			rules.add(rule);
        			List<ScoreRuleItemDto> items = new ArrayList<>();
        			rule.setItems(items);
        			for(PhysicalRuleItemDto physicalItem : physicalRuleItemList) {
        				if(compareValue(physicalRule.getId(), physicalItem.getRuleId())) {
        					ScoreRuleItemDto item = new ScoreRuleItemDto();
        					item.setId(physicalItem.getId());
        					item.setSex(physicalRule.getSex());
        					item.setMin(physicalItem.getMin());
        					item.setMax(physicalItem.getMax());
							item.setScoreLevel(Integer.parseInt(physicalItem.getName()));
        					item.setScore(physicalItem.getScore());
        					if (item.getScore() > rule.getScore()){
        						rule.setScore(item.getScore());
							}
        					items.add(item);
        				}
        			}
        			List<ScoreRulePlusDto> pluses = new ArrayList<>();
        			rule.setPluses(pluses);
        			for(PhysicalRulePlusesDto physicalPlus : physicalRulePlusList) {
        				if(compareValue(physicalRule.getId(), physicalPlus.getRuleId())) {
        					ScoreRulePlusDto plus = new ScoreRulePlusDto();
        					plus.setId(physicalPlus.getId());
        					plus.setSex(physicalRule.getSex());
        					plus.setMin(physicalPlus.getMin());
        					plus.setMax(physicalPlus.getMax());
        					plus.setScore(physicalPlus.getScore());
							if (plus.getScore() > rule.getPlusScore()){
								rule.setPlusScore(plus.getScore());
							}
        					pluses.add(plus);
        				}
        			}
        		}
        	}
        }
        
        
        Map<String, ScoreRuleDto> ruleMaps = new TreeMap<>();
        
        for(ScoreRuleDto rule : rules) {
        	String key = rule.findKey();
        	if(!ruleMaps.containsKey(key)) {
        		ruleMaps.put(key, rule);
        	}else {
        		ScoreRuleDto dto = ruleMaps.get(key);
        		dto.getItems().addAll(rule.getItems());
        		dto.getPluses().addAll(rule.getPluses());
        	}
        }
        
        rules = new ArrayList<>(ruleMaps.values());
        for(ScoreRuleDto rule : rules) {
        	List<ScoreScope> scopes = new ArrayList<>();
        	rule.setScoreScopes(scopes);
        	ScoreScope maleScope = getScoreScope((byte)1, rule.getItems(), rule.getPluses());
        	scopes.add(maleScope);
        	ScoreScope femaleScope = getScoreScope((byte)2, rule.getItems(), rule.getPluses());
        	scopes.add(femaleScope);
        }
        
        return rules;
	}
	
    private ScoreScope getScoreScope(byte gender, List<ScoreRuleItemDto> items, List<ScoreRulePlusDto> pluses) {
    	ScoreScope scope = new ScoreScope();
    	scope.setGender(gender);
    	int max = 0;
		for(ScoreRuleItemDto item : items) {
			if(item.getSex() == gender) {
				if(item.getMin() > max) {
					max = (int)item.getMin();
				}
			}
		}
		scope.setMaxCount(max);
		max = 0;
		for(ScoreRulePlusDto plus : pluses) {
			if(plus.getSex() == gender) {
				if(plus.getMin() > max) {
					max = (int)plus.getMin();
				}
			}
		}
		scope.setMaxPlusCount(max);
		return scope;
	}
	
	private boolean compareValue(Number n1, Number n2) {
    	if(n1 == null || n2 == null) {
    		return false;
    	}
    	if(n1 instanceof Long) {
    		return n1.longValue() == n2.longValue();
    	}
    	if(n1 instanceof Byte) {
    		return n1.byteValue() == n2.byteValue();
    	}
    	return n1.intValue() == n2.intValue();
    }

}
